#include "BlockQueue.hpp"
#include <sys/types.h>
#include <cstdlib>
#include "Task.hpp"

// 基于阻塞队列的生产者消费者模型的实现
const string oper = "+-*/%";
int mymath(int x, int y, char op)
{
    int result;
    switch (op)
    {
    case '+':
        result = x + y;
        break;
    case '-':
        result = x - y;
        break;
    case '*':
        result = x * y;
        break;
    case '/':
    {
        if (y == 0)
        {
            cout << "不能/0\n";
            break;
        }
        result = x / y;
        break;
    }

    case '%':
    {
        if (y == 0)
        {
            cout << "不能%0";
            break;
        }
        result = x % y;
        break;
    }

    default:
        cout << "error oper" << endl;
        break;
    }

    return result;
}

void *comsume(void *blockqueue)
{
    BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(blockqueue);
    // 消费——往阻塞队列取数据
    while (true)
    {
        Task t;
        bq->pop(&t);
        printf("消费任务：%s\n", t().c_str());
        // sleep(1); // 利用sleep控制消费的速度
    }

    return nullptr;
}

void *productor(void *blockqueue)
{
    BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(blockqueue);
    // 生产——往阻塞队列放数据
    while (true)
    {
        // 生产一个任务
        int x = rand() % 10 + 1; //+1是不想看到0，%10+1是想控制在1~10
        int y = rand() % 10 + 1;
        int index = rand() % oper.size(); // 获取下标，从而随机获取计算符
        Task t(x, y, oper[index], mymath);

        bq->push(t);
        printf("生产任务：%s\n", t.toTackString().c_str());
        sleep(1); // 利用sleep控制生产的速度
    }

    return nullptr;
}

int main()
{
    srand((unsigned int)time(nullptr) ^ getpid());
    BlockQueue<Task> *bq = new BlockQueue<Task>(); // 创建一个阻塞队列

    // // 创建一个生产者线程，一个消费者线程
    // pthread_t c, p;
    // pthread_create(&c, nullptr, comsume, bq);
    // pthread_create(&p, nullptr, productor, bq);

    // pthread_join(c, nullptr);
    // pthread_join(p, nullptr);

    // 创建3个生产者线程，2个消费者线程
    pthread_t c[2], p[3];
    pthread_create(p, nullptr, productor, bq);
    pthread_create(p + 1, nullptr, productor, bq);
    pthread_create(p + 2, nullptr, productor, bq);
    pthread_create(c, nullptr, comsume, bq);
    pthread_create(c + 1, nullptr, comsume, bq);

    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);
    pthread_join(p[2], nullptr);

    delete bq;

    return 0;
}